package com.sojson.service.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sojson.config.exception.TransException;
import com.sojson.dao.RoleDao;
import com.sojson.dao.RoleMenuDao;
import com.sojson.dao.UserRoleDao;
import com.sojson.entity.po.Role;
import com.sojson.entity.po.RoleMenu;
import com.sojson.enums.EIsUnique;
import com.sojson.service.RoleService;
import com.sojson.util.StringUtil;
import com.sojson.util.security.springsecurity.service.PermissionService;
import com.sojson.util.token.Token;
import com.sojson.util.token.TokenUtil;

/**
 * 角色信息表Service实现类
 * 
 * @author liu
 * @date 2021-04-13
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleServiceImpl roleServiceImpl;
    @Autowired
    private PermissionService permissionService;
    @Resource
    private RoleDao roleDaoImpl;
    @Resource
    private RoleMenuDao roleMenuDaoImpl;
    @Resource
    private UserRoleDao userRoleDaoImpl;

    /**
     * 单条插入
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    @Transactional
    public int insert(Role role) throws SQLException {
        if (EIsUnique.NO.getCode() == roleServiceImpl.checkRoleKeyUnique(role)) {
            throw new TransException("新增角色'" + role.getName() + "'失败，角色权限已存在");
        }

        roleDaoImpl.insert(role);
        return insertRoleMenu(role);
    }

    /**
     * 修改角色菜单信息
     *
     * @param role 角色对象
     */
    @Transactional
    public int updateRoleMenu(Role role) {
        // 删除角色与菜单关联
        roleMenuDaoImpl.deleteByRoleId(role.getId());
        return roleServiceImpl.insertRoleMenu(role);
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    @Transactional
    public int insertRoleMenu(Role role) {
        int rows = 1;
        Integer[] menuIds = role.getMenuIds();
        if (StringUtil.isBlankObject(menuIds) || menuIds.length < 1) {
            return rows;
        }
        // 新增用户与角色管理
        List<RoleMenu> list = new ArrayList<>();
        Integer id = role.getId();
        for (Integer menuId : menuIds) {
            RoleMenu rm = new RoleMenu();
            rm.setRoleId(id);
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
            rows = roleMenuDaoImpl.insertList(list);
        }
        return rows;
    }

    /**
     * 批量插入
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int insertList(Role role) throws SQLException {
        int insertList = roleDaoImpl.insertList(role.getRoles());
        return insertList;
    }

    /**
     * 通过对象批量删除(物理删除)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByDto(Role role) throws SQLException {
        int deleteByDto = roleDaoImpl.deleteByDto(role);
        return deleteByDto;
    }

    /**
     * 统计全部数量
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public int countAll() throws SQLException {
        int countAll = roleDaoImpl.countAll();
        return countAll;
    }

    /**
     * 查询所有
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public List<Role> findAll() throws SQLException {
        List<Role> findAll = roleDaoImpl.listAll();
        return findAll;
    }

    /**
     * 根据对象统计数量
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int countByDto(Role role) throws SQLException {
        int countByDto = roleDaoImpl.countByDto(role);
        return countByDto;
    }

    /**
     * 根据对象查询
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public List<Role> findByDto(Role role) throws SQLException {
        List<Role> findByDto = roleDaoImpl.listByDto(role);
        return findByDto;
    }

    /**
     * 通过id删除(物理删除)
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteById(Integer id) throws SQLException {
        int deleteById = roleDaoImpl.deleteById(id);
        return deleteById;
    }

    /**
     * 通过id列表删除(物理删除)
     * 
     * @param ids
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByIdList(ArrayList<Integer> ids) throws SQLException {
        int deleteByIdList = roleDaoImpl.deleteByIdList(ids);
        return deleteByIdList;
    }

    /**
     * 通过id更新(全部更新)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int updateById(Role role) throws SQLException {
        int updateById = roleDaoImpl.updateById(role);
        return updateById;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容相同)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int updateStaticByIdList(Role role) throws SQLException {
        int updateStaticByIdList = roleDaoImpl.updateStaticByIdList(role);
        return updateStaticByIdList;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容不相同)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int updateChangeByIdList(Role role) throws SQLException {
        int updateChangeByIdList = roleDaoImpl.updateChangeByIdList(role.getRoles());
        return updateChangeByIdList;
    }

    /**
     * 通过id更新(局部更新)
     * 
     * @param role
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePartialById(Role role) throws Exception {
        // 校验角色是否允许操作
        checkRoleAllowed(role);

        // 修改角色
        int updatePartialById = roleDaoImpl.updatePartialById(role);
        // 添加角色与菜单关联
        roleServiceImpl.updateRoleMenu(role);

        if (updatePartialById > 0) {
            // 更新缓存用户权限
            Token token = TokenUtil.getToken();
            if (StringUtil.isNotBlankObject(token.getMember()) && !TokenUtil.isAdmin(token.getMember().getId())) {
                token.setPermissions(permissionService.getMenuPermission(token.getMember()));
                TokenUtil.refreshToken(token);
            }
        }
        return updatePartialById;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容相同)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int updateStaticPartialByIdList(Role role) throws SQLException {
        int updateStaticPartialByIdList = roleDaoImpl.updateStaticPartialByIdList(role);
        return updateStaticPartialByIdList;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容不相同)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int updateChangePartialByIdList(Role role) throws SQLException {
        int updateChangePartialByIdList = roleDaoImpl.updateChangePartialByIdList(role.getRoles());
        return updateChangePartialByIdList;
    }

    /**
     * 通过id查询
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public Role findById(Integer id) throws SQLException {
        Role findById = roleDaoImpl.findById(id);
        return findById;
    }

    /**
     * 通过id列表查询
     * 
     * @param ids
     * @return
     * @throws SQLException
     */
    @Override
    public ArrayList<Role> findByIdList(ArrayList<Integer> ids) throws SQLException {
        ArrayList<Role> findByIdList = roleDaoImpl.findByIdList(ids);
        return findByIdList;
    }

    /**
     * 通过对象查询id列表
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public ArrayList<Integer> findIdByDto(Role role) throws SQLException {
        ArrayList<Integer> findIdByDto = roleDaoImpl.findIdByDto(role);
        return findIdByDto;
    }

    /**
     * 通过对象删除(逻辑删除)
     * 
     * @param role
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByDtoAndUpdate(Role role) throws SQLException {
        int deleteByDtoAndUpdate = roleDaoImpl.deleteByDtoAndUpdate(role);
        return deleteByDtoAndUpdate;
    }

    /**
     * 统计所有未删除的数据
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public int countAllAndStatusNo() throws SQLException {
        int countAllAndStatusNo = roleDaoImpl.countAllAndStatusNo();
        return countAllAndStatusNo;
    }

    /**
     * 查询所有未删除的数据
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public ArrayList<Role> findAllAndStatusNo() throws SQLException {
        ArrayList<Role> findAllAndStatusNo = roleDaoImpl.findAllAndStatusNo();
        return findAllAndStatusNo;
    }

    /**
     * 通过id删除(逻辑删除)
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByIdAndUpdate(Integer id) throws SQLException {
        int deleteByIdAndUpdate = roleDaoImpl.deleteByIdAndUpdate(id);
        return deleteByIdAndUpdate;
    }

    /**
     * 通过id列表删除(逻辑删除)
     * 
     * @param ids
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByIdListAndUpdate(ArrayList<Integer> ids) throws SQLException {
        int deleteByIdListAndUpdate = roleDaoImpl.deleteByIdListAndUpdate(ids);
        return deleteByIdListAndUpdate;
    }

    /**
     * 清空数据(物理清空)
     * 
     * @throws SQLException
     */
    @Override
    public void clear() throws SQLException {
        roleDaoImpl.clear();
    }

    /**
     * 清空数据(逻辑清空)
     * 
     * @throws SQLException
     */
    @Override
    public void clearAndUpdate() throws SQLException {
        roleDaoImpl.clearAndUpdate();
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return
     */
    @Override
    public Set<String> getRolePermissionByUserId(Integer userId) {
        Set<Role> rolePermissionByUserId = roleDaoImpl.getRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (Role perm : rolePermissionByUserId) {
            if (StringUtil.isNotBlankObject(perm)) {
                permsSet.addAll(Arrays.asList(perm.getKey().trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public Integer checkRoleKeyUnique(Role role) {
        Integer id = role.getId();
        Integer roleId = StringUtil.isBlankObject(id) ? -1 : id;
        Role info = roleDaoImpl.checkRoleKeyUnique(role.getKey());
        if (StringUtil.isNotBlankObject(info) && info.getId().intValue() != roleId.intValue()) {
            return EIsUnique.NO.getCode();
        }
        return EIsUnique.YES.getCode();
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    @Override
    public void checkRoleAllowed(Role role) {
        if (StringUtil.isNotBlankObject(role.getId()) && role.isAdmin()) {
            throw new TransException("不允许操作超级管理员角色");
        }
    }

    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int authDataScope(Role role) {
        // 校验角色是否允许操作
        checkRoleAllowed(role);

        // 修改角色
        return roleDaoImpl.updatePartialById(role);
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int updateRoleStatus(Role role) {
        // 校验角色是否允许操作
        checkRoleAllowed(role);

        // 修改角色
        return roleDaoImpl.updatePartialById(role);
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     * @throws SQLException 
     */
    @Override
    public int deleteRoleByIds(Integer[] roleIds) throws SQLException {
        for (Integer roleId : roleIds) {
            checkRoleAllowed(new Role(roleId));
            Role role = findById(roleId);
            if (countUserRoleByRoleId(roleId) > 0) {
                throw new TransException(String.format("%1$s已分配,不能删除", role.getName()));
            }
        }
        return roleDaoImpl.deleteByIdListAndUpdateArr(roleIds);
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    public int countUserRoleByRoleId(Integer roleId) {
        return userRoleDaoImpl.countUserRoleByRoleId(roleId);
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     * @throws SQLException 
     */
    @Override
    public List<Role> selectRoleAll() throws SQLException {
        return findByDto(new Role());
    }

}